#include "objectsystemNEWER.h"

#define HIBYTE(val) ((val&0xFF00)>>8)
#define LOBYTE(val) (val&0x00FF)
#define LONGTOWORD(val) ((val&0xFFFF0000)>>16)
#define SWAPWORD(val) (((val&0xFF00)>>8) + ((val&0x00FF)<<8))

object* objects = new object[127];

extern byte v_zone;
extern long v_screenposx, v_screenposy;

byte v_opl_routine;
word *v_opl_data[4];

byte v_objstate[0x200];
signed short v_opl_screen;

void (*OPL_Index[2])() = { OPL_Main, OPL_Next };
/*; ===========================================================================
OPL_Index:	dc.w OPL_Main-OPL_Index
		dc.w OPL_Next-OPL_Index
; ===========================================================================*/

extern byte ObjPos_GHZ1[];
byte *ObjPos_Null = 0;

byte *ObjPos_Index[2/*72*/] = {                 
                ObjPos_GHZ1, ObjPos_Null  /*, ObjPos_GHZ2, ObjPos_Null, ObjPos_GHZ3, ObjPos_Null, ObjPos_GHZ1, ObjPos_Null,
		ObjPos_LZ1,  ObjPos_Null,  ObjPos_LZ2, ObjPos_Null,  ObjPos_LZ3, ObjPos_Null, ObjPos_SBZ3, ObjPos_Null,
		ObjPos_MZ1,  ObjPos_Null,  ObjPos_MZ2, ObjPos_Null,  ObjPos_MZ3, ObjPos_Null,  ObjPos_MZ1, ObjPos_Null,
		ObjPos_SLZ1, ObjPos_Null, ObjPos_SLZ2, ObjPos_Null, ObjPos_SLZ3, ObjPos_Null, ObjPos_SLZ1, ObjPos_Null,
		ObjPos_SYZ1, ObjPos_Null, ObjPos_SYZ2, ObjPos_Null, ObjPos_SYZ3, ObjPos_Null, ObjPos_SYZ1, ObjPos_Null,
		ObjPos_SBZ1, ObjPos_Null, ObjPos_SBZ2, ObjPos_Null,   ObjPos_FZ, ObjPos_Null, ObjPos_SBZ1, ObjPos_Null,
		ObjPos_End,  ObjPos_Null,  ObjPos_End, ObjPos_Null,  ObjPos_End, ObjPos_Null,  ObjPos_End, ObjPos_Null,
		
                ObjPos_LZ1pf1,   ObjPos_LZ1pf2,  ObjPos_LZ2pf1, ObjPos_LZ2pf2,   ObjPos_LZ3pf1,  ObjPos_LZ3pf2,  ObjPos_LZ1pf1,  ObjPos_LZ1pf2,
		ObjPos_SBZ1pf1, ObjPos_SBZ1pf2, ObjPos_SBZ1pf3, ObjPos_SBZ1pf4, ObjPos_SBZ1pf5, ObjPos_SBZ1pf6, ObjPos_SBZ1pf1, ObjPos_SBZ1pf2 */
}; 

//ObjPosLoad:				; XREF: GM_Level; et al
void ObjPosLoad()
{
    //moveq	#0,d0
    //move.b	(v_opl_routine).w,d0
    byte routine = v_opl_routine;

    //move.w	OPL_Index(pc,d0.w),d0
    //jmp	OPL_Index(pc,d0.w)
    (*OPL_Index[routine/2])();
    
}   //; End of function ObjPosLoad

//OPL_Main:				; XREF: OPL_Index
void OPL_Main()
{
    //addq.b	#2,(v_opl_routine).w
    v_opl_routine = v_opl_routine + 2;           //OPL_Main is the init subroutine, calling ObjPosLoad next time shall skip to OPL_Next-therefore OPL_Main is only run once
		
    //move.w	(v_zone).w,d0
    //lsl.b	#6,d0
    //lsr.w	#4,d0
    word zone = v_zone * 2;                      //calculating offset of correct 2 pointers in ObjPos_Index for current zone
                                                 //only first pointer is used, second is NULL per each zone
    //lea	(ObjPos_Index).l,a0
    
    //movea.l	a0,a1
    //adda.w	(a0,d0.w),a0
    word *objectX = (word*)ObjPos_Index[zone];   //points to list of entrys: (X pos, Y pos, ?) for each object in zone (GRABS XPOS IF DEREFERENCED) 
    
    //move.l	a0,(v_opl_data).w
    //move.l	a0,(v_opl_data+4).w              //(v_opl_data[0] and v_opl_data[1] iterate through zone "object position list" separately)
    v_opl_data[0] = objectX;                     //v_opl_data[0] points to beginning of list of objects to iterate through (for now)
    v_opl_data[1] = objectX;                     //v_opl_data[1] also points to beginning of list (for now)

    //adda.w	2(a1,d0.w),a1
    word *objectY = (word*)ObjPos_Index[zone] + 1;//points to list of entrys + 1 word: (Y pos, ?, X pos next obj) for each object in zone (GRABS YPOS IF DEREFERENCED)

    //move.l	a1,(v_opl_data+8).w
    //move.l	a1,(v_opl_data+$C).w             //(v_opl_data[2] and v_opl_data[3] unused)
    v_opl_data[2] = objectY;                     //v_opl_data[2] points to beginning of list + 1 of objects to iterate through
    v_opl_data[3] = objectY;                     //v_opl_data[3] also points to beginning of list + 1 

    //lea	(v_objstate).w,a2
    byte *statePtr = v_objstate;                 //statePtr points to object state list (records object counts while iterating through "object position list")

    //move.w	#$101,(a2)+
    *(statePtr++) = 0x01;                        //state list BYTE 1 = # of objects to respawn > 2/5 of viewport size offscreen left
    *(statePtr++) = 0x01;                        //state list BYTE 2 = # of objects to respawn > 4/5 of viewport size offscreen left

    //move.w	#$5E,d0
    signed short listSize = 0x5E*4;              //2 + 0x5E = 0x60 bytes in state list

    //OPL_ClrList:
    //clr.l	(a2)+
    //dbf	d0,OPL_ClrList	; clear	pre-destroyed object list
    for (;listSize>=0; listSize--)
        *(statePtr++) = 0;
    //----------------------------------------------

    //lea	(v_objstate).w,a2
    statePtr = v_objstate;                                 //reset statePtr at beginning of state list

    //moveq	#0,d2

    //move.w	(v_screenposx).w,d6
    //subi.w	#$80,d6
    signed short screenX = LONGTOWORD(v_screenposx) - 128; //screenX at first refers to 128 pixels to the left of screen...

    //bhs.s	loc_D93C
    //moveq	#0,d6
    if (screenX < 0) { screenX = 0; }                      //(if 128 pixels left of screen still refers to play area, aka not out of bounds)

    //loc_D93C:
    //andi.w	#$FF80,d6
    screenX = screenX & 0xFF80;                            //rounds to 1 single 128 pixel section to the left of screen 
 
    //movea.l	(v_opl_data).w,a0
    word *objPos = v_opl_data[0];                          //objPos a copy of iterator 'v_opl_data[0]' at beginning of object position list

    byte objState;
    //loc_D944:
    //cmp.w	(a0),d6                                    //screenX 1 single 128 pixel section to left of screen so:
    //bls.s	loc_D956                                   //if screenX >= index 1 (x position) of current object pointed to by objPos
    while (screenX >= SWAPWORD(objPos[0]))                 //then this object is more than 128 pixels to the left of viewport, so...
    {
        //tst.b	4(a0)
	//bpl.s	loc_D952
        if ((signed char)HIBYTE(SWAPWORD(objPos[2])) < 0)     //if this object should respawn (bit 7 of high byte in index 3 (byte 5 if 6 byte entrys and not 3 word))
        {
	    //move.b	(a2),d2
            objState = statePtr[0];                               //objstate = 1 less than statePtr[0]

            //addq.b	#1,(a2)
            statePtr[0] = statePtr[0] + 1;                        //add to # of objects to respawn > 2/5 of viewport size offscreen left
        }

        //loc_D952:
	//addq.w	#6,a0
        objPos = objPos + 3;                                  //objPos incremented by size of 1 object position entry, for check the next object in the list
        
    }   //bra.s	loc_D944
    //; ===========================================================================

    //loc_D956:
    //move.l	a0,(v_opl_data).w
    v_opl_data[0] = objPos;                               //v_opl_data[0] updated to refer to first object in list that ISN'T more than 128 pixels left of viewport


    //movea.l	(v_opl_data+4).w,a0
    objPos = v_opl_data[1];                               //objPos now a copy of iterator 'v_opl_data[1]' at beginning of object position list                       

    //subi.w	#$80,d6
    signed short offscreenX = screenX - 128;              //subtract another 128 pixel section from current (128 pixels left of screen) yielding 2 128 pixel sections left of screen (256 pixels)

    //blo.s	loc_D976
    if (offscreenX >= 0)                                  //if (2 128 pixels sections) 256 pixels left of screen refers to valid position in play area
    {
        //loc_D964:                                  
	//cmp.w	(a0),d6                                   //screenX 2 128 pixel sections to left of screen so:
        //bls.s	loc_D976                                  //if screenX >= index 1 (x position) of current object pointed to by objPos
        while (offscreenX >= SWAPWORD(objPos[0]))         //then this object is more than 256 pixels to the left of viewport, so...
        {
	    //tst.b	4(a0)
	    //bpl.s	loc_D972
            if ((signed char)HIBYTE(SWAPWORD(objPos[2])) < 0)     //if this object should respawn (bit 7 of high byte in index 3 (byte 5 if 6 byte entrys and not 3 word))
            {
		//addq.b	#1,1(a2)
                statePtr[1] = statePtr[1] + 1;                    //add to # of objects to respawn left of 4/5 of viewport size offscreen left
            }   
            
            //loc_D972:
	    //addq.w	#6,a0
            objPos = objPos + 3;                              //objPos incremented by size of 1 object position entry, for check the next object in the list
 
	}   //bra.s	loc_D964
    }
    //; ===========================================================================

    //loc_D976:
    //move.l	a0,(v_opl_data+4).w
    v_opl_data[1] = objPos;                                   //v_opl_data[1] updated to refer to first object in list that ISN'T more than 256 pixels left of viewport (i.e first object right of...)


    //move.w	#-1,(v_opl_screen).w
    v_opl_screen = -1;                                        //used as previous screen location, initial value is -1 for always pass the condition in OPL_Next (screen never negative)

    OPL_Next();
}

//OPL_Next:				; XREF: OPL_Index
void OPL_Next()
{
    //lea	(v_objstate).w,a2
    byte *statePtr = v_objstate;

    //moveq	#0,d2
    byte objstate = 0;

    //move.w	(v_screenposx).w,d6
    //andi.w	#$FF80,d6
    signed short screenX = LONGTOWORD(v_screenposx) & 0xFF80;     //current screen position in terms of 128 pixel sections

    //cmp.w	(v_opl_screen).w,d6
    //beq.w	locret_DA3A
    if (screenX != v_opl_screen)                                  //v_opl_screen refers to previous screen position, IF CHANGE IN SCREEN POSITION
    {
        //bge.s	loc_D9F6
        if (screenX < v_opl_screen)                               //if screen has since moved left (by 128 pix)...
        {
            //move.w	d6,(v_opl_screen).w
            v_opl_screen = screenX;                               //update v_opl_screen for check next time around

	    //movea.l	(v_opl_data+4).w,a0
            word *objPos = v_opl_data[1];                         //first object previously known as to the right of (1 128 pix sections) 128 pix offscreen left of viewport
 
	    #define offscreenLeftX screenX
            //subi.w	#$80,d6
            offscreenLeftX = screenX - 128;                       //refers to 1 128 pixel section offscreen left of viewport

	    //blo.s	loc_D9D2
            if (offscreenLeftX >= 0)                              //(if 128 pixels left of screen still refers to play area, aka not out of bounds)
            {
                long itemSuccess = 0;

                //loc_D9A6:
		//cmp.w	-6(a0),d6
                while ((offscreenLeftX < SWAPWORD(objPos[-3])) && (itemSuccess == 0)) //for each of these objects to the right of (1 128 pix sections) 128 pix offscreen left of viewport
                {
                    //bge.s	loc_D9D2
		    //subq.w	#6,a0
		    objPos = objPos - 3;                          //objPos decremented for each object left of 256 pix offscreen

                    //tst.b	4(a0)
                    //bpl.s	loc_D9BC
                    if ((signed char)HIBYTE(SWAPWORD(objPos[2])) < 0) //if this object should respawn (bit 7 of high byte in index 3 (byte 5 if 6 byte entrys and not 3 word))
                    {
		        //subq.b	#1,1(a2)
                        statePtr[1] = statePtr[1] - 1;            //subtract from # of objects to respawn left of 4/5 of viewport size offscreen left
  
                        //move.b	1(a2),d2
                        objstate = statePtr[1];
                    }

                    //loc_D9BC:
		    //bsr.w	loc_DA3C
                    itemSuccess = MakeItem(objPos, statePtr, objstate);

                    //bne.s	loc_D9C6
                    if (itemSuccess == 0)
                    {
                        //subq.w	#6,a0
	                objPos = objPos - 3;
                   
                        //bra.s	loc_D9A6
                    }   //beginning of while loop...
 		    else
                    {
                        //loc_D9C6:
		        //tst.b	4(a0)
                        //bpl.s	loc_D9D0
                        if ((signed char)HIBYTE(SWAPWORD(objPos[2])) < 0)
		        {
		            //addq.b	#1,1(a2)
                            statePtr[1] = statePtr[1] + 1;
                        }
    
                        //loc_D9D0:
		        //addq.w	#6,a0
                        objPos = objPos + 3;
 
                    }   //doesnt normally go to beginning of while loop, but this works because itemsuccess!=0 automatically breaks it
                    //; ===========================================================================
 
                }   
            }
	  
            //loc_D9D2:
	    //move.l	a0,(v_opl_data+4).w
            v_opl_data[1] = objPos;

	    
            //movea.l	(v_opl_data).w,a0
            objPos = v_opl_data[0];
 
            #define offscreenRightX screenX
	    //addi.w	#$300,d6
            offscreenRightX = offscreenLeftX + 768;

            //loc_D9DE:
	    //cmp.w	-6(a0),d6
            //bgt.s	loc_D9F0
            while (offscreenRightX <= SWAPWORD(objPos[-3]))
            {
		
                //tst.b	-2(a0)
                //bpl.s	loc_D9EC
                if ((signed char)HIBYTE(SWAPWORD(objPos[-1])) < 0)
                {
		    //subq.b	#1,(a2)
                    statePtr[0] = statePtr[0] - 1;
                }
                
                //loc_D9EC:
		//subq.w	#6,a0
                objPos = objPos - 3;
		
            }   //bra.s	loc_D9DE
            		
            //; ===========================================================================

            //loc_D9F0:
            //move.l	a0,(v_opl_data).w
            v_opl_data[0] = objPos;

            //rts                               
            //; ===========================================================================
        }
        else
        {

            //loc_D9F6:
	    //move.w	d6,(v_opl_screen).w
            v_opl_screen = screenX;                                                    //update v_opl_screen for check next time around
         
	    //movea.l	(v_opl_data).w,a0
            word *objPos = v_opl_data[0];                                              //

            #define offscreenRightXEnd screenX
	    //addi.w	#$280,d6
            offscreenRightXEnd = offscreenRightX + 640;                                //

            long itemSuccess = 0;
            //loc_DA02:
 	    //cmp.w	(a0),d6
            //bls.s	loc_DA16
            while ((offscreenRightXEnd >= SWAPWORD(objPos[0])) && (itemSuccess == 0))  
            { 
                
	        //tst.b	4(a0)
	        //bpl.s	loc_DA10
                if ((signed char)HIBYTE(SWAPWORD(objPos[2])) < 0)
                {
		    //move.b	(a2),d2
		    objstate = statePtr[0];
 
                    //addq.b	#1,(a2)
                    statePtr[0] = statePtr[0] + 1;
                }
                
                //loc_DA10:
	        //bsr.w	loc_DA3C
	        itemSuccess = MakeItem(objPos, statePtr, objstate);
                
            }   //beq.s	loc_DA02

            //loc_DA16:
	    //move.l	a0,(v_opl_data).w
            v_opl_data[0] = objPos;

	    //movea.l	(v_opl_data+4).w,a0
            objPos = v_opl_data[1];

            #define offscreenLeftXEnd screenX
	    //subi.w	#$300,d6
            offscreenLeftXEnd = offscreenRightXEnd - 0x300;

	    //blo.s	loc_DA36
            if (offscreenLeftXEnd >= 0)
            {
                //loc_DA24:
	        //cmp.w	(a0),d6
	        //bls.s	loc_DA36
                while (offscreenLeftXEnd >= SWAPWORD(objPos[0])) 
	        {
                    
                    //tst.b	4(a0)
	            //bpl.s	loc_DA32
		    if ((signed char)HIBYTE(SWAPWORD(objPos[2])) < 0)
                    {
                        //addq.b	#1,1(a2)
                        statePtr[1] = statePtr[1] + 1;
                    }
                    
                    //loc_DA32:
		    //addq.w	#6,a0
		    objPos = objPos + 3;

                }   //bra.s	loc_DA24
                //; ===========================================================================
            }
            //loc_DA36:
	    //move.l	a0,(v_opl_data+4).w
            v_opl_data[1] = objPos;
        }
    }  //locret_DA3A:
}      //rts	
//; ===========================================================================


long MakeItem(word* &objPos, byte *stateList, word objNum)
{
    //loc_DA3C:
    //tst.b	4(a0)
    if ((signed char)HIBYTE(SWAPWORD(objPos[2])) >= 0)
    {
        //bpl.s	OPL_MakeItem
        return OPL_MakeItem(objPos, objNum);
    }
    else
    {           
        #define objInList 2+objNum
        byte oldstate = stateList[objInList] & 0x80;
        
        //bset	#7,2(a2,d2.w)
        stateList[objInList] = stateList[objInList] | 0x80;

	//beq.s	OPL_MakeItem
        if (oldstate == 0) { return OPL_MakeItem(objPos, objNum); }
        else
        {
            //addq.w	#6,a0
            objPos = objPos + 3;

	    //moveq	#0,d0
            return 0;

	    //rts
        }
    }
}   //; ===========================================================================

//OPL_MakeItem:
long OPL_MakeItem(word* &objPos, byte objNum)
{
    //bsr.w	FindFreeObj
    object *newObject = FindFreeObj();

    //bne.s	locret_DA8A
    if (newObject != 0 && (newObject->ID==0))
    {
        //move.w	(a0)+,obX(a1)
        newObject->X = SWAPWORD(*(objPos++));
          
	//move.w	(a0)+,d0 
        word obY = SWAPWORD(*(objPos++));

        //move.w	d0,d1
	//andi.w	#$FFF,d0
        word newY = obY & 0xFFF;
 
	//move.w	d0,obY(a1)
        newObject->Y = newY;

        //rol.w	#2,d1
	//andi.b	#3,d1
        byte obOriBits = ((obY << 2) | (obY >> 14)) & 3;

	//move.b	d1,obRender(a1)
        newObject->Render = obOriBits;

	//move.b	d1,obStatus(a1)
        newObject->Status = obOriBits;

        word objPosSpawnSub = SWAPWORD(*(objPos++));
	
        //move.b	(a0)+,d0
        signed char objRespawn = HIBYTE(objPosSpawnSub);

	//bpl.s	loc_DA80
        if (objRespawn < 0)
        { 
            #define obRespawnNo objRespawn
	    
            //andi.b	#$7F,d0
            obRespawnNo = objRespawn & 0x7F;

	    //move.b	d2,obRespawnNo(a1)
            newObject->RespawnNo = objNum;
        }

        //loc_DA80:
	//move.b	d0,0(a1)
        newObject->ID = objRespawn;

	//move.b	(a0)+,obSubtype(a1)
        newObject->Subtype = LOBYTE(objPosSpawnSub);

	//moveq	#0,d0
        return 0;
    
    }   //locret_DA8A:
    return 1;
}       //rts	

//; ---------------------------------------------------------------------------
//; Subroutine to remember whether an object is destroyed/collected
//; ---------------------------------------------------------------------------
#include "sprite.h"

//RememberState:
void RememberState(object *obj)
{
    //out_of_range	@offscreen 
    //bra.w	DisplaySprite
    if (!out_of_range(obj))
        DisplaySprite(obj);
    else
    {
        //@offscreen:
	//lea	(v_objstate).w,a2
        byte *statePtr = v_objstate;

	//moveq	#0,d0
	//move.b	obRespawnNo(a0),d0
        byte respawn = obj->RespawnNo;

	//beq.s	@delete
        if (respawn != 0)
        {
	    //bclr	#7,2(a2,d0.w)
            statePtr[2+respawn] = statePtr[2+respawn] - (statePtr[2+respawn] & 128);
        }
	
        //@delete:
	//bra.w	DeleteObject
        DeleteObject(obj);
    }
}

bool out_of_range(object *obj)
{
    return out_of_range(obj->X);
}

//out_of_range:	macro exit,pos
bool out_of_range(word compareX)
{
    //if (narg=2)
    //move.w	pos,d0		; get object position (if specified as not obX)
    
 
    //else
    //move.w	obX(a0),d0	; get object position
    //endc

    //andi.w	#$FF80,d0	; round down to nearest $80
    word pos = compareX & 0xFF80;
   
    //move.w	(v_screenposx).w,d1 ; get screen position
    //subi.w	#128,d1
    word screenX = LONGTOWORD(v_screenposx) - 128;

    //andi.w	#$FF80,d1
    screenX = screenX & 0xFF80;

    //sub.w	d1,d0		; approx distance between object and screen
    signed short distObjScreen = pos - screenX;  

    //cmpi.w	#128+320+192,d0
    if (distObjScreen > (128+320+192)) { return true; }
    else if (distObjScreen < -((128+320+192)*2)) { return true; }
    else { return false; }

    //bhi.\0	exit
    //endm
}



//FindFreeObj:
object *FindFreeObj()
{
    //lea	(v_objspace+$800).w,a1 ; start address for object RAM
    //byte *objRAM = v_objspace;

    //move.w	#$5F,d0
    signed short numObjs = 0x5F;

    //FFree_Loop:
    for (int obj=0; numObjs>=0; numObjs--,obj++)
    {
        //tst.b	(a1)		; is object RAM	slot empty?
        //beq.s	FFree_Found	; if yes, branch
        if (objects[obj].ID == 0) { return &objects[obj]; }
        //if (objRAM[0] == 0) { return &objRAM[0]; }
		
	//lea	$40(a1),a1	; goto next object RAM slot
        //objRAM = objRAM + 0x40;

    }   //dbf	d0,FFree_Loop	; repeat $5F times
    
    return 0;
}   //FFree_Found:
    //rts	
